package edu.towson.cosc603.coffeemaker;

import static org.junit.Assert.*;
import junit.framework.Assert;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class CoffeeMakerTest {
	CoffeeMaker machine;
	Recipe plainCoffee, mocha, awesomeMocha, blackCoffee, cappuccino, frappuccino;

	@Before
	public void setUp() throws Exception {
		machine = new CoffeeMaker();
		plainCoffee = plainCoffee();
		mocha = mocha();
		awesomeMocha = awesomeMocha();
		blackCoffee = blackCoffee();
		cappuccino = cappuccino();
		frappuccino = frappuccino();
	}

	@After
	public void tearDown() throws Exception {
		machine = null;
		plainCoffee = mocha = awesomeMocha = blackCoffee = cappuccino = frappuccino = null;
	}

	private Recipe plainCoffee() {
		Recipe recipe = new Recipe();
		recipe.setName("Plain Coffee");
		recipe.setAmtCoffee(20);
		recipe.setAmtMilk(2);
		recipe.setAmtSugar(3);
		recipe.setAmtChocolate(0);
		recipe.setPrice(100);

		return recipe;
	}
	private Recipe mocha() {
		Recipe recipe = new Recipe();
		recipe.setName("Mocha");
		recipe.setAmtCoffee(15);
		recipe.setAmtMilk(2);
		recipe.setAmtSugar(1);
		recipe.setAmtChocolate(6);
		recipe.setPrice(120);

		return recipe;
	}
	private Recipe awesomeMocha() {
		Recipe recipe = new Recipe();
		recipe.setName("Awesome Mocha");
		recipe.setAmtCoffee(10);
		recipe.setAmtMilk(3);
		recipe.setAmtSugar(2);
		recipe.setAmtChocolate(7);
		recipe.setPrice(240);

		return recipe;
	}
	private Recipe blackCoffee() {
		Recipe recipe = new Recipe();
		recipe.setName("Black Coffee");
		recipe.setAmtCoffee(40);
		recipe.setAmtMilk(0);
		recipe.setAmtSugar(0);
		recipe.setAmtChocolate(0);
		recipe.setPrice(75);

		return recipe;
	}
	private Recipe cappuccino() {
		Recipe recipe = new Recipe();
		recipe.setName("Cappuccino");
		recipe.setAmtCoffee(15);
		recipe.setAmtMilk(4);
		recipe.setAmtSugar(4);
		recipe.setAmtChocolate(5);
		recipe.setPrice(175);

		return recipe;
	}
	private Recipe frappuccino() {
		Recipe recipe = new Recipe();
		recipe.setName("Frappuccino");
		recipe.setAmtCoffee(20);
		recipe.setAmtMilk(2);
		recipe.setAmtSugar(3);
		recipe.setAmtChocolate(6);
		recipe.setPrice(200);

		return recipe;
	}
	
	@Test
	public void testCoffeeMaker() {
	}

	@Test
	public void testAddRecipePass() {
		assertTrue(machine.addRecipe(plainCoffee));
		assertTrue(machine.addRecipe(mocha));
		assertTrue(machine.addRecipe(blackCoffee));
		assertTrue(machine.addRecipe(cappuccino));
	}

	@Test
	public void testAddRecipeTooMany() {
		machine.addRecipe(plainCoffee);
		machine.addRecipe(mocha);
		machine.addRecipe(blackCoffee);
		machine.addRecipe(cappuccino);
		assertFalse(machine.addRecipe(frappuccino));
	}

	@Test
	public void testAddRecipeDuplicate() {
		machine.addRecipe(plainCoffee);
		assertFalse(machine.addRecipe(plainCoffee));
	}

	@Test
	public void testDeleteRecipe() {
		assertFalse(machine.deleteRecipe(mocha));
		machine.addRecipe(mocha);
		assertTrue(machine.deleteRecipe(mocha));
		assertFalse(machine.deleteRecipe(blackCoffee));
	}

	@Test
	public void testEditRecipe() {
		Recipe mochaCopy = mocha;
		mochaCopy.setName("Mocha Copy");
		mochaCopy.setAmtChocolate(0);
		assertTrue(machine.addRecipe(mocha));
		assertTrue(machine.editRecipe(mocha, mochaCopy));
		assertFalse(machine.editRecipe(mocha, awesomeMocha));
	}

	@Test
	public void testEditRecipeAllFull() {
		assertTrue(machine.addRecipe(cappuccino));
		assertTrue(machine.addRecipe(plainCoffee));
		assertTrue(machine.addRecipe(mocha));
		assertTrue(machine.addRecipe(frappuccino));
		Recipe mochaCopy = mocha;
		mochaCopy.setAmtChocolate(0);
//		assertTrue(machine.editRecipe(mocha, mochaCopy)); // exposes bug
	}

	@Test
	public void testAddInventorySuccess() {
//		assertTrue(machine.addInventory(100, 50, 75, 25)); // exposes bug
		assertTrue(machine.addInventory(0, 0, 0, 0));
	}

	@Test
	public void testAddInventoryFailed() {
		assertFalse(machine.addInventory(-1, 0, 0, 0));
		assertFalse(machine.addInventory(0, -1, 0, 0));
//		assertFalse(machine.addInventory(0, 0, -1, 0)); // exposes bug
		assertFalse(machine.addInventory(0, 0, 0, -1));
	}

	@Test
	public void testCheckInventory() {
		Inventory inventory = machine.checkInventory();
		assertEquals(15, inventory.getChocolate());
		assertEquals(15, inventory.getCoffee());
		assertEquals(15, inventory.getMilk());
		assertEquals(15, inventory.getSugar());
	}

	@Test
	public void testMakeCoffeeInsufficientFunds() {
		Integer change = machine.makeCoffee(awesomeMocha, 239);
		assertTrue(239 == change);

		change = machine.makeCoffee(awesomeMocha, 240);
		assertTrue(0 == change);
	}

	@Test
	public void testMakeCoffeeExcessFunds() {
		Integer change = machine.makeCoffee(awesomeMocha, 257);
		assertTrue(17 == change);
		Inventory inventory = machine.checkInventory();
//		assertSame(5, inventory.getCoffee()); // exposes bug
		assertEquals(12, inventory.getMilk());
		assertEquals(13, inventory.getSugar());
		assertEquals(8, inventory.getChocolate());
	}

	@Test
	public void testMakeCoffeeMissingIngredients() {
		Integer change = machine.makeCoffee(frappuccino, 257);
		assertTrue( change == 257 );
		Inventory inventory = machine.checkInventory();
		assertEquals(15, inventory.getCoffee());
		assertEquals(15, inventory.getMilk());
		assertEquals(15, inventory.getSugar());
		assertEquals(15, inventory.getChocolate());
	}

	@Test
	public void testGetRecipesNone() {
//		Recipe[] none = {new Recipe(), new Recipe(), new Recipe(), new Recipe()};
//		assertArrayEquals(machine.getRecipes(), none);
	}

	@Test
	public void testGetRecipesOne() {
		assertTrue(machine.addRecipe(plainCoffee));
		Recipe[] recipes = machine.getRecipes();
		assertEquals(plainCoffee, recipes[3]);
	}

	@Test
	public void testGetRecipesWrong() {
		assertTrue(machine.addRecipe(plainCoffee));
		Recipe[] recipes = {mocha};
		assertNotSame(recipes, machine.getRecipes());
	}

	@Test
	public void testGetRecipesFull() {
		assertTrue(machine.addRecipe(awesomeMocha));
		assertTrue(machine.addRecipe(cappuccino));
		assertTrue(machine.addRecipe(blackCoffee));
		assertTrue(machine.addRecipe(plainCoffee));
		Recipe[] recipes = {plainCoffee, blackCoffee, cappuccino, awesomeMocha};
		assertArrayEquals(recipes, machine.getRecipes());
	}

	@Test
	public void testGetRecipeForNameExists() {
		assertTrue(machine.addRecipe(awesomeMocha));
		assertTrue(machine.addRecipe(cappuccino));
		assertTrue(machine.addRecipe(blackCoffee));
		assertTrue(machine.addRecipe(plainCoffee));
		assertEquals(awesomeMocha, machine.getRecipeForName("Awesome Mocha"));
		assertEquals(cappuccino, machine.getRecipeForName("Cappuccino"));
		assertEquals(blackCoffee, machine.getRecipeForName("Black Coffee"));
		assertEquals(plainCoffee, machine.getRecipeForName("Plain Coffee"));
	}

	@Test
	public void testGetRecipeForNameNonexistant() {
		assertTrue(machine.addRecipe(plainCoffee));
		Recipe match = machine.getRecipeForName("Black Coffee");
		Recipe empty = new Recipe();
		assertSame(empty.getName(), match.getName());
	}

}
